|
| 1 | +//===--- DependencyCollector.h -------------------------------- -*- C++ -*-===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2020 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 | +// This file defines a class for recording incremental dependencies. |
| 14 | +// |
| 15 | +//===----------------------------------------------------------------------===// |
| 16 | + |
| 17 | +#ifndef SWIFT_AST_DEPENDENCY_COLLECTOR_H |
| 18 | +#define SWIFT_AST_DEPENDENCY_COLLECTOR_H |
| 19 | + |
| 20 | +#include "swift/AST/Identifier.h" |
| 21 | +#include "llvm/ADT/DenseMap.h" |
| 22 | +#include "llvm/ADT/DenseSet.h" |
| 23 | + |
| 24 | +namespace swift { |
| 25 | + |
| 26 | +class NominalTypeDecl; |
| 27 | + |
| 28 | +namespace evaluator { |
| 29 | + |
| 30 | +class DependencyRecorder; |
| 31 | + |
| 32 | +/// A \c DependencyCollector defines an abstract write-only buffer of |
| 33 | +/// \c Reference objects. References are added to a collector during the write |
| 34 | +/// phase of request evaluation (in \c writeDependencySink) with the various |
| 35 | +/// \c add* functions below. |
| 36 | +/// |
| 37 | +/// A \c DependencyCollector should not be created directly; instances are |
| 38 | +/// vended by the request evaluator infrastructure itself. |
| 39 | +struct DependencyCollector { |
| 40 | + friend DependencyRecorder; |
| 41 | + |
| 42 | + struct Reference { |
| 43 | + public: |
| 44 | + enum class Kind { |
| 45 | + Empty, |
| 46 | + Tombstone, |
| 47 | + UsedMember, |
| 48 | + PotentialMember, |
| 49 | + TopLevel, |
| 50 | + Dynamic, |
| 51 | + } kind; |
| 52 | + |
| 53 | + NominalTypeDecl *subject; |
| 54 | + DeclBaseName name; |
| 55 | + |
| 56 | + private: |
| 57 | + Reference(Kind kind, NominalTypeDecl *subject, DeclBaseName name) |
| 58 | + : kind(kind), subject(subject), name(name) {} |
| 59 | + |
| 60 | + public: |
| 61 | + static Reference empty() { |
| 62 | + return {Kind::Empty, llvm::DenseMapInfo<NominalTypeDecl *>::getEmptyKey(), |
| 63 | + llvm::DenseMapInfo<DeclBaseName>::getEmptyKey()}; |
| 64 | + } |
| 65 | + |
| 66 | + static Reference tombstone() { |
| 67 | + return {Kind::Tombstone, |
| 68 | + llvm::DenseMapInfo<NominalTypeDecl *>::getTombstoneKey(), |
| 69 | + llvm::DenseMapInfo<DeclBaseName>::getTombstoneKey()}; |
| 70 | + } |
| 71 | + |
| 72 | + public: |
| 73 | + static Reference usedMember(NominalTypeDecl *subject, DeclBaseName name) { |
| 74 | + return {Kind::UsedMember, subject, name}; |
| 75 | + } |
| 76 | + |
| 77 | + static Reference potentialMember(NominalTypeDecl *subject) { |
| 78 | + return {Kind::PotentialMember, subject, DeclBaseName()}; |
| 79 | + } |
| 80 | + |
| 81 | + static Reference topLevel(DeclBaseName name) { |
| 82 | + return {Kind::TopLevel, nullptr, name}; |
| 83 | + } |
| 84 | + |
| 85 | + static Reference dynamic(DeclBaseName name) { |
| 86 | + return {Kind::Dynamic, nullptr, name}; |
| 87 | + } |
| 88 | + |
| 89 | + public: |
| 90 | + struct Info { |
| 91 | + static inline Reference getEmptyKey() { return Reference::empty(); } |
| 92 | + static inline Reference getTombstoneKey() { |
| 93 | + return Reference::tombstone(); |
| 94 | + } |
| 95 | + static inline unsigned getHashValue(const Reference &Val) { |
| 96 | + return llvm::hash_combine(Val.kind, Val.subject, |
| 97 | + Val.name.getAsOpaquePointer()); |
| 98 | + } |
| 99 | + static bool isEqual(const Reference &LHS, const Reference &RHS) { |
| 100 | + return LHS.kind == RHS.kind && LHS.subject == RHS.subject && |
| 101 | + LHS.name == RHS.name; |
| 102 | + } |
| 103 | + }; |
| 104 | + }; |
| 105 | + |
| 106 | +private: |
| 107 | + DependencyRecorder &parent; |
| 108 | + |
| 109 | +public: |
| 110 | + explicit DependencyCollector(DependencyRecorder &parent); |
| 111 | + ~DependencyCollector(); |
| 112 | + |
| 113 | +public: |
| 114 | + /// Registers a named reference from the current dependency scope to a member |
| 115 | + /// defined in the given \p subject type. |
| 116 | + /// |
| 117 | + /// Used member constraints are typically the by-product of direct lookups, |
| 118 | + /// where the name being looked up and the target of the lookup are known |
| 119 | + /// up front. A used member dependency causes the file to be rebuilt if the |
| 120 | + /// definition of that member changes in any way - via |
| 121 | + /// deletion, addition, or mutation of a member with that same name. |
| 122 | + void addUsedMember(NominalTypeDecl *subject, DeclBaseName name); |
| 123 | + /// Registers a reference from the current dependency scope to a |
| 124 | + /// "potential member" of the given \p subject type. |
| 125 | + /// |
| 126 | + /// A single potential member dependency can be thought of as many used member |
| 127 | + /// dependencies - one for each current member of the subject type, but also |
| 128 | + /// one for every member that will be added or removed from the type in the |
| 129 | + /// future. As such, these dependencies cause rebuilds when any members are |
| 130 | + /// added, removed, or changed in the \p subject type. It also indicates a |
| 131 | + /// dependency on the \p subject type's existence, so deleting the \p subject |
| 132 | + /// type will also cause a rebuild. |
| 133 | + /// |
| 134 | + /// These dependencies are most appropriate for protocol conformances, |
| 135 | + /// superclass constraints, and other requirements involving entire types. |
| 136 | + void addPotentialMember(NominalTypeDecl *subject); |
| 137 | + /// Registers a reference from the current dependency scope to a given |
| 138 | + /// top-level \p name. |
| 139 | + /// |
| 140 | + /// A top level dependency causes a rebuild when another top-level entity with |
| 141 | + /// that name is added, removed, or modified. |
| 142 | + void addTopLevelName(DeclBaseName name); |
| 143 | + /// Registers a reference from the current dependency scope to a given |
| 144 | + /// dynamic member \p name. |
| 145 | + /// |
| 146 | + /// A dynamic lookup dependency is a special kind of member dependency on |
| 147 | + /// a name that is found by \c AnyObject lookup. |
| 148 | + void addDynamicLookupName(DeclBaseName name); |
| 149 | + |
| 150 | +public: |
| 151 | + /// Retrieves the dependency recorder that created this dependency collector. |
| 152 | + const DependencyRecorder &getRecorder() const { return parent; } |
| 153 | +}; |
| 154 | + |
| 155 | +} // end namespace evaluator |
| 156 | + |
| 157 | +} // end namespace swift |
| 158 | + |
| 159 | +#endif // SWIFT_AST_DEPENDENCY_COLLECTOR_H |
0 commit comments