Skip to content

Commit 709c58a

Browse files
author
David Ungar
authored
Merge pull request #29869 from davidungar/unit-test-users-v4
[Incremental] Reorganization of SourceFileDepGraph building and mocking.
2 parents 42e8a96 + 6fa6b98 commit 709c58a

11 files changed

+1688
-1262
lines changed

include/swift/AST/FineGrainedDependencies.h

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,20 @@ template <typename KeyT, typename ValueT> class Memoizer {
9393
public:
9494
Memoizer() = default;
9595

96+
Optional<ValueT> findExisting(KeyT key) {
97+
auto iter = memos.find(key);
98+
if (iter != memos.end())
99+
return iter->second;
100+
return None;
101+
}
102+
96103
/// \p createFn must create a \ref ValueT that corresponds to the \ref KeyT
97104
/// passed into it.
98105
ValueT
99106
findExistingOrCreateIfNew(KeyT key,
100107
function_ref<ValueT(const KeyT &)> createFn) {
101-
auto iter = memos.find(key);
102-
if (iter != memos.end())
103-
return iter->second;
108+
if (auto existing = findExisting(key))
109+
return existing.getValue();
104110
ValueT v = createFn(key);
105111
(void)insert(key, v);
106112
return v;
@@ -372,6 +378,7 @@ const std::string NodeKindNames[]{
372378
"topLevel", "nominal", "potentialMember", "member",
373379
"dynamicLookup", "externalDepend", "sourceFileProvide"};
374380

381+
375382
/// Instead of the status quo scheme of two kinds of "Depends", cascading and
376383
/// non-cascading this code represents each entity ("Provides" in the status
377384
/// quo), by a pair of nodes. One node represents the "implementation." If the
@@ -391,6 +398,7 @@ template <typename FnT> void forEachAspect(FnT fn) {
391398
fn(DeclAspect(i));
392399
}
393400

401+
394402
/// A pair of nodes that represent the two aspects of a given entity.
395403
/// Templated in order to serve for either SourceFileDepGraphNodes or
396404
/// ModuleDepGraphNodes.
@@ -499,10 +507,23 @@ class DependencyKey {
499507
}
500508
bool isInterface() const { return getAspect() == DeclAspect::interface; }
501509

510+
/// Create just the interface half of the keys for a provided Decl or Decl
511+
/// pair
512+
template <NodeKind kind, typename Entity>
513+
static DependencyKey createForProvidedEntityInterface(Entity);
514+
502515
/// Given some type of provided entity compute the context field of the key.
503516
template <NodeKind kind, typename Entity>
504517
static std::string computeContextForProvidedEntity(Entity);
505518

519+
DependencyKey correspondingImplementation() const {
520+
return withAspect(DeclAspect::implementation);
521+
}
522+
523+
DependencyKey withAspect(DeclAspect aspect) const {
524+
return DependencyKey(kind, aspect, context, name);
525+
}
526+
506527
/// Given some type of provided entity compute the name field of the key.
507528
template <NodeKind kind, typename Entity>
508529
static std::string computeNameForProvidedEntity(Entity);
@@ -514,7 +535,8 @@ class DependencyKey {
514535
template <NodeKind kind>
515536
static DependencyKey createDependedUponKey(StringRef);
516537

517-
static DependencyKey createKeyForWholeSourceFile(StringRef swiftDeps);
538+
static DependencyKey createKeyForWholeSourceFile(DeclAspect,
539+
StringRef swiftDeps);
518540

519541
std::string humanReadableName() const;
520542

@@ -555,6 +577,14 @@ struct std::hash<typename swift::fine_grained_dependencies::DeclAspect> {
555577
return size_t(aspect);
556578
}
557579
};
580+
template <>
581+
struct std::hash<typename swift::fine_grained_dependencies::NodeKind> {
582+
size_t
583+
operator()(const swift::fine_grained_dependencies::NodeKind kind) const {
584+
return size_t(kind);
585+
}
586+
};
587+
558588

559589
namespace swift {
560590
namespace fine_grained_dependencies {
@@ -616,6 +646,10 @@ class DepGraphNode {
616646
/// See SourceFileDepGraphNode::SourceFileDepGraphNode(...) and
617647
/// ModuleDepGraphNode::ModuleDepGraphNode(...) Don't set swiftDeps on
618648
/// creation because this field can change if a node is moved.
649+
DepGraphNode(DependencyKey key, Optional<StringRef> fingerprint)
650+
: DepGraphNode(key, fingerprint ? fingerprint->str()
651+
: Optional<std::string>()) {}
652+
619653
DepGraphNode(DependencyKey key, Optional<std::string> fingerprint)
620654
: key(key), fingerprint(fingerprint) {}
621655
DepGraphNode(const DepGraphNode &other) = default;
@@ -627,8 +661,12 @@ class DepGraphNode {
627661

628662
const DependencyKey &getKey() const { return key; }
629663

630-
const Optional<std::string> &getFingerprint() const { return fingerprint; }
631-
664+
const Optional<StringRef> getFingerprint() const {
665+
if (fingerprint) {
666+
return StringRef(fingerprint.getValue());
667+
}
668+
return None;
669+
}
632670
/// When driver reads a SourceFileDepGraphNode, it may be a node that was
633671
/// created to represent a name-lookup (a.k.a a "depend") in the frontend. In
634672
/// that case, the node represents an entity that resides in some other file
@@ -637,7 +675,9 @@ class DepGraphNode {
637675
/// (someday) have a fingerprint. In order to preserve the
638676
/// ModuleDepGraphNode's identity but bring its fingerprint up to date, it
639677
/// needs to set the fingerprint *after* the node has been created.
640-
void setFingerprint(Optional<std::string> fp) { fingerprint = fp; }
678+
void setFingerprint(Optional<StringRef> fp) {
679+
fingerprint = fp ? fp->str() : Optional<std::string>();
680+
}
641681

642682
SWIFT_DEBUG_DUMP;
643683
void dump(llvm::raw_ostream &os) const;
@@ -684,7 +724,7 @@ class SourceFileDepGraphNode : public DepGraphNode {
684724
SourceFileDepGraphNode() : DepGraphNode(), sequenceNumber(~0) {}
685725

686726
/// Used by the frontend to build nodes.
687-
SourceFileDepGraphNode(DependencyKey key, Optional<std::string> fingerprint,
727+
SourceFileDepGraphNode(DependencyKey key, Optional<StringRef> fingerprint,
688728
bool isProvides)
689729
: DepGraphNode(key, fingerprint), isProvides(isProvides) {
690730
assert(key.verify());
@@ -780,34 +820,6 @@ class SourceFileDepGraph {
780820
SourceFileDepGraph(const SourceFileDepGraph &g) = delete;
781821
SourceFileDepGraph(SourceFileDepGraph &&g) = default;
782822

783-
/// Simulate loading for unit testing:
784-
/// \param swiftDepsFileName The name of the swiftdeps file of the phony job
785-
/// \param includePrivateDeps Whether the graph includes intra-file arcs
786-
/// \param hadCompilationError Simulate a compilation error
787-
/// \param interfaceHash The interface hash of the simulated graph
788-
/// \param simpleNamesByRDK A map of vectors of names keyed by reference
789-
/// dependency key \param compoundNamesByRDK A map of (mangledHolder,
790-
/// baseName) pairs keyed by reference dependency key. For single-name
791-
/// dependencies, an initial underscore indicates that the name does not
792-
/// cascade. For compound names, it is the first name, the holder which
793-
/// indicates non-cascading. For member names, an initial underscore indicates
794-
/// file-privacy.
795-
static SourceFileDepGraph
796-
simulateLoad(std::string swiftDepsFileName, const bool includePrivateDeps,
797-
const bool hadCompilationError, std::string interfaceHash,
798-
llvm::StringMap<std::vector<std::string>> simpleNamesByRDK,
799-
llvm::StringMap<std::vector<std::pair<std::string, std::string>>>
800-
compoundNamesByRDK);
801-
802-
static constexpr char noncascadingOrPrivatePrefix = '#';
803-
static constexpr char nameFingerprintSeparator = ',';
804-
805-
static std::string noncascading(std::string name);
806-
807-
LLVM_ATTRIBUTE_UNUSED
808-
static std::string privatize(std::string name);
809-
810-
811823
/// Nodes are owned by the graph.
812824
~SourceFileDepGraph() {
813825
forEachNode([&](SourceFileDepGraphNode *n) { delete n; });
@@ -851,12 +863,15 @@ class SourceFileDepGraph {
851863
/// The frontend creates a pair of nodes for every tracked Decl and the source
852864
/// file itself.
853865
InterfaceAndImplementationPair<SourceFileDepGraphNode>
854-
findExistingNodePairOrCreateAndAddIfNew(
855-
NodeKind k, const ContextNameFingerprint &contextNameFingerprint);
866+
findExistingNodePairOrCreateAndAddIfNew(const DependencyKey &interfaceKey,
867+
Optional<StringRef> fingerprint);
868+
869+
NullablePtr<SourceFileDepGraphNode>
870+
findExistingNode(const DependencyKey &key);
856871

857872
SourceFileDepGraphNode *
858-
findExistingNodeOrCreateIfNew(DependencyKey key,
859-
const Optional<std::string> &fingerprint,
873+
findExistingNodeOrCreateIfNew(const DependencyKey &key,
874+
const Optional<StringRef> fingerprint,
860875
bool isProvides);
861876

862877
/// \p Use is the Node that must be rebuilt when \p def changes.
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
//===----- SourceFileDepGraphConstructor.h ----------------------*- C++ -*-===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef SWIFT_AST_SOURCE_FILE_DEP_GRAPH_CONSTRUCTOR_H
14+
#define SWIFT_AST_SOURCE_FILE_DEP_GRAPH_CONSTRUCTOR_H
15+
16+
#include <swift/AST/DeclContext.h>
17+
18+
namespace swift {
19+
namespace fine_grained_dependencies {
20+
/// Abstract class for building a \c SourceFileDepGraph from either a real
21+
/// \c SourceFile or a unit test
22+
class SourceFileDepGraphConstructor {
23+
protected:
24+
/// To match the existing system, set this to false.
25+
/// To include even private entities and get intra-file info, set to true.
26+
const bool includePrivateDeps;
27+
28+
/// If there was an error, cannot get accurate info.
29+
const bool hadCompilationError;
30+
31+
/// The name of the swiftDeps file.
32+
const std::string swiftDeps;
33+
34+
/// The fingerprint of the whole file
35+
const std::string fileFingerprint;
36+
37+
/// For debugging
38+
const bool emitDotFileAfterConstruction;
39+
40+
DiagnosticEngine &diags;
41+
42+
/// Graph under construction
43+
SourceFileDepGraph g;
44+
45+
public:
46+
/// Expose this layer to enable faking up a constructor for testing.
47+
/// See the instance variable comments for explanation.
48+
SourceFileDepGraphConstructor(bool includePrivateDeps,
49+
bool hadCompilationError, StringRef swiftDeps,
50+
StringRef fileFingerprint,
51+
bool emitDotFileAfterConstruction,
52+
DiagnosticEngine &diags);
53+
54+
virtual ~SourceFileDepGraphConstructor() = default;
55+
56+
/// Create a SourceFileDepGraph.
57+
SourceFileDepGraph construct();
58+
59+
private:
60+
void addSourceFileNodesToGraph();
61+
62+
/// Add the "provides" nodes when mocking up a graph
63+
virtual void addAllDefinedDecls() = 0;
64+
65+
/// Add the "depends" nodes and arcs when mocking a graph
66+
virtual void addAllUsedDecls() = 0;
67+
68+
protected:
69+
/// Add an pair of interface, implementation nodes to the graph, which
70+
/// represent some \c Decl defined in this source file. \param key the
71+
/// interface key of the pair
72+
void addADefinedDecl(const DependencyKey &key,
73+
Optional<StringRef> fingerprint);
74+
75+
void addAUsedDecl(const DependencyKey &def, const DependencyKey &use);
76+
};
77+
78+
/// Constructs a SourceFileDepGraph from a *real* \c SourceFile
79+
/// Reads the information provided by the frontend and builds the
80+
/// SourceFileDepGraph
81+
82+
class RealSourceFileDepGraphConstructor : public SourceFileDepGraphConstructor {
83+
SourceFile *const SF;
84+
const DependencyTracker &depTracker;
85+
86+
public:
87+
RealSourceFileDepGraphConstructor(SourceFile *SF, StringRef outputPath,
88+
const DependencyTracker &depTracker,
89+
bool alsoEmitDotFile);
90+
91+
~RealSourceFileDepGraphConstructor() override = default;
92+
93+
private:
94+
static std::string getFingerprint(SourceFile *SF);
95+
96+
static bool computeIncludePrivateDeps(SourceFile *SF);
97+
static std::string getInterfaceHash(SourceFile *SF);
98+
99+
void addAllDefinedDecls() override;
100+
void addAllUsedDecls() override;
101+
102+
/// Given an array of Decls or pairs of them in \p declsOrPairs
103+
/// create node pairs for context and name
104+
template <NodeKind kind, typename ContentsT>
105+
void addAllDefinedDeclsOfAGivenType(std::vector<ContentsT> &contentsVec);
106+
107+
/// At present, only nominals, protocols, and extensions have (body)
108+
/// fingerprints
109+
static Optional<std::string>
110+
getFingerprintIfAny(std::pair<const NominalTypeDecl *, const ValueDecl *>);
111+
static Optional<std::string> getFingerprintIfAny(const Decl *d);
112+
};
113+
114+
using DependencyDescriptions =
115+
std::unordered_multimap<NodeKind, std::vector<std::string>>;
116+
117+
class MockSourceFileDepGraphConstructor : public SourceFileDepGraphConstructor {
118+
const DependencyDescriptions dependencyDescriptions;
119+
120+
public:
121+
MockSourceFileDepGraphConstructor(
122+
bool includePrivateDeps, bool hadCompilationError, StringRef swiftDeps,
123+
StringRef fileFingerprint, bool emitDotFileAfterConstruction,
124+
const DependencyDescriptions &dependencyDescriptions,
125+
DiagnosticEngine &diags)
126+
: SourceFileDepGraphConstructor(includePrivateDeps, hadCompilationError,
127+
swiftDeps, fileFingerprint,
128+
emitDotFileAfterConstruction, diags),
129+
dependencyDescriptions(dependencyDescriptions) {}
130+
131+
~MockSourceFileDepGraphConstructor() override = default;
132+
133+
private:
134+
void addAllDefinedDecls() override;
135+
void addAllUsedDecls() override;
136+
137+
/// For brevity, unit tests specify dependencies by NodeKind,
138+
/// but for processing, the kind is needed for each entry.
139+
void forEachEntry(function_ref<void(NodeKind kind, StringRef entry)> fn);
140+
141+
static const char *defUseSeparator;
142+
static bool isADefinedDecl(StringRef s);
143+
144+
void addADefinedDecl(StringRef s, NodeKind kind);
145+
void addAUsedDecl(StringRef s, NodeKind kind);
146+
147+
Optional<std::pair<DependencyKey, DependencyKey>> parseAUsedDecl(StringRef s,
148+
NodeKind);
149+
150+
/// Parse and return an interface \c DependencyKey
151+
Optional<DependencyKey> parseADefinedDecl(StringRef s, NodeKind, DeclAspect);
152+
153+
DependencyKey computeUseKey(StringRef s, bool isCascadingUse);
154+
155+
/// Return true if when the name appears in a unit test, it represents a
156+
/// context, not a baseName. Return false if a single name is a baseName,
157+
/// without context Return None if there shoud be two names
158+
static Optional<bool> singleNameIsContext(NodeKind kind);
159+
160+
static constexpr char nameContextSeparator = ',';
161+
162+
static constexpr char fingerprintSeparator = '@';
163+
164+
static std::string parseContext(const StringRef s, const NodeKind kind);
165+
166+
static std::string parseName(const StringRef s, const NodeKind kind);
167+
};
168+
169+
} // namespace fine_grained_dependencies
170+
} // namespace swift
171+
172+
#endif // SWIFT_AST_SOURCE_FILE_DEP_GRAPH_CONSTRUCTOR_H

0 commit comments

Comments
 (0)